List of Packages used;
- caret
- corrplot
- dplyr
- missForest

library(e1071) # to understand skewness
library(dplyr)
library(stringr) # Used to rename the columns by removing the word team from the column header
library(VIM) # To understand NAs
library(caret)
library("MASS") # to use for robust Linear Regression.
# browse to the data
moneyball = read.csv('/Users/legs_jorge/Documents/Data Science Projects/MSDS_Northwestern/MSDS 411/Unit 01 Moneyball Baseball Problem/Data/moneyball.csv', header = T)
colnames(moneyball) <- str_replace_all(colnames(moneyball),"TEAM_","") %>% 
  tolower() # Fixing column names

Data Exploration

Steps

  1. Outliers/influencial Points in Independent and Dependent variables
  2. Homogeneity
  3. Normality of Dependent variable
  4. Zero trouble of Dependent variable
  5. Collinearity of Independent variables
  6. Relationps Between Independent and Dependent variables
  7. Interactions
  8. Independence of Dependent variable

Step 1: Can we find outliers in our Independent and Dependent variables?

Outliers can cause our model to produce the wrong output by influencing its fit. Creating boxplots will aid in identifying those outliers. We can also use the cleveland dotplot to understand the outliers better. This technique uses the row number against actual value to quickly point out any patterns of outliers. This plot will easilly allow us to check the raw data for errors such as typos during the data collection phase. Points on the far right side, or on the far left side, are observed values that are considerably larger, or smaller, than the majority of the observations, and require further investigation. When we use this chart, together with the box plot and histogram, we can easily identify patterns at to where in the data we’re seeing outliers.

par(mfrow = c(1, 3))
i = 2
while (i %in% c(2:17)) {
 
plot(moneyball[,i], moneyball$index, xlab = colnames(moneyball)[i] , ylab = "Index", main = paste("cleveland dotplot of ",colnames(moneyball)[i]))
boxplot(moneyball[,i], col = "#A71930", main = paste("Boxplot of ",colnames(moneyball)[i]))
hist(
  moneyball[,i],
  col = "#A71930",
  xlab = colnames(moneyball)[i],
  main = paste("Histogram of ",colnames(moneyball)[i])
)
  i = i + 1
}

It looks like the outliers are legitmate and we will try two techniques to deal with them;
1. Use Robust linear Regression
2. Use Spatial Sign transformation after scaling and centering the data.

Now that step one is done, let’s look at step 2.

Step 2: Are the data normally distributed?

From the historgram above we can clearly see that the data is not normal, with the exception of some that seems to sort of follow a normal distribution. Let’s use QQ-plot to test each column for normality, while adding a histogram and a Skewness number.
- If skewness is less than −1 or greater than +1, the distribution is highly skewed.
- If skewness is between −1 and −½ or between +½ and +1, the distribution is moderately skewed.
- If skewness is between −½ and +½, the distribution is approximately symmetric.

par(mfrow = c(2, 2))
i = 2
while (i %in% c(2:17)) {
  qqnorm(moneyball[,i], main = paste("QQ-Plot of ",colnames(moneyball)[i]));qqline(moneyball[,i], col = 2)
  
  hist(
  moneyball[,i],
  col = "#A71930",
  xlab = colnames(moneyball)[i],
  main = paste0("Skewness = ",skewness(moneyball[,i]))
)
  
  i = i + 1
  
}

We would need to try certain transformation to correct for Skewness, with Box-Cox being the number one choice.

Step 4: Are there lots of NAs in the data?

R gives us a lot of ways to understand the distribution of Nulls within the data. Let’s first try to calculate the percentage of Null values to the total number of observation.

NAPerc <-
  sapply(moneyball, function(x)
    (sum(is.na(x)) / length(x)) * 100) %>%
  data.frame()
NAPerc$Column <- rownames(NAPerc)
colnames(NAPerc) <- c("NA_Perc", "Col_Name")
# Trying to understand the percentage of NAs per Column
NA_col <- subset(NAPerc, NA_Perc > 0) %>% arrange(desc(NA_Perc))
NA_col
NA_subset <- moneyball[, c(NA_col$Col_Name)]
matrixplot(NA_subset, labels = TRUE, interactive = TRUE)

Click in a column to sort by the corresponding variable.
To regain use of the VIM GUI and the R console, click outside the plot region.

Let’s look at the pattern of missing data to try to get more insights. It’s clear that TEAM_BATTING_HBP is going to be a problematic column with 92% of the data missing. Before we start the imputation, let’s try to understand why we have missing data.

There are two types of missing data

  • MCAR: missing completely at random. This is the desirable scenario in case of missing data.
  • MNAR: missing not at random. Missing not at random data is a more serious issue and in this case it might be wise to check the data gathering process further and try to understand why the information is missing. For instance, if most of the people in a survey did not answer a certain question, why did they do that? Was the question unclear?
    It would be good to understand exactly what type of missing value we are dealing with.

Let’s use the mice package to help us understant how all the NAs behave in the data. mice provides a handy function called md.pattern that allows one to understand the pattern of missing data. Hopefully by looking at the pattern, we can have an idea on why the data could be missing.

md.pattern(moneyball) %>% data.frame()

The first column of the output shows the number of unique missing data patterns. There are 191 observations with nonmissing values, and there are 1295 observations with nonmissing values except for the variable batting_hbp. The rightmost column shows the number of missing variables in a particular missing pattern. For example, the first row has no missing value and it is “0” in the row. The last row counts the number of missing values for each variable. For example, the variable pitching_bb contains no missing values and the variable batting_so contains 102 missing values. This table can be helpful when you decide to drop some observations with missing variables exceeding a preset threshold.

After doing some reading it looks like that columns could be translated to a 0 or 1. I need to do more investigating. From working experience, usually columns with high volumes of NAs indicates important informations, simply because they could be capturing rare instance where a process fails. Instead of deleting it, I will try to see if I can transform it into a categorical variable with 1s and 0s. Now, regarding the other one, I will try some other inputation methods such as KNN, mean, median, etc.

Step 5: Is there collinearity among the covariates?

Let’s create a series of scatter plots to understand how each independent variable interacts with the dependent variable. These scatter plots will help us spot any infrigement of the assupmtions needed to develop a robust OLS model, namely multicollinearity.

chart.Correlation(moneyball, histogram = TRUE, pch = 1, method = c("pearson"))

In the above plot:

The distribution of each variable is shown on the diagonal. On the bottom of the diagonal : the bivariate scatter plots with a fitted line displayed on the top of the diagonal: the value of the correlation plus the significance level as stars. Each significance level is associated to a symbol: p-values(0, 0.001, 0.01, 0.05, 0.1, 1) <=> symbols(“***”, “**”, “*”, “.”, " “)

As we go across the second row, we notice that variables aren’t strongly correlated to our target variable. One can also notice correlation numbers up to 0.97 among our independent variables. Those variables will pose a problem when you include them in a model.

The Caret package offers the findcorrelation(), which takes the correlation matrix as an input and finds the fields causing multicollinearity based on a threshold, the cutoff parameter. It in turns returns a vector with values that would need to be removed from our dataset due to correlation.

paste0("Need to exclude ", colnames(moneyball)[findCorrelation(cor(moneyball))])
[1] "Need to exclude batting_hr"

We will need to revisit this after we have imputed/taken care of Nulls.

Data Transformation

Before we start scaling, centering, or apply any other modification to the dataset, let make sure we have taken care of the null values. Let’s first focus on the columns with the highest volume of nulls, batting_hbp.

For this column we will try to transform it into a binary variable, 1s and 0s. I don’t understand baseball, but it seems that this variable is not missing at random, so we could simple say Hitt by pitch or not. I will also see if imputation using the MICE package will help in any way.

moneyball_trans <- subset(moneyball_trans, select = -c(batting_hbp)) # Dropping the variable we just transformed. 
Error in eval(expr, envir, enclos) : object 'batting_hbp' not found

Now that that variable is taken care of, let’s start imputing missing values using mice. Since we only have numeric values, mice will automatically chose PMM (Predictive Mean Matching)

Now that we have imputed the data, let’s do a quick summary of the data to see how it looks like.

summary(moneyball_trans)
     index         target_wins       batting_h      batting_2b      batting_3b       batting_hr       batting_bb   
 Min.   :   1.0   Min.   :  0.00   Min.   : 891   Min.   : 69.0   Min.   :  0.00   Min.   :  0.00   Min.   :  0.0  
 1st Qu.: 630.8   1st Qu.: 71.00   1st Qu.:1383   1st Qu.:208.0   1st Qu.: 34.00   1st Qu.: 42.00   1st Qu.:451.0  
 Median :1270.5   Median : 82.00   Median :1454   Median :238.0   Median : 47.00   Median :102.00   Median :512.0  
 Mean   :1268.5   Mean   : 80.79   Mean   :1469   Mean   :241.2   Mean   : 55.25   Mean   : 99.61   Mean   :501.6  
 3rd Qu.:1915.5   3rd Qu.: 92.00   3rd Qu.:1537   3rd Qu.:273.0   3rd Qu.: 72.00   3rd Qu.:147.00   3rd Qu.:580.0  
 Max.   :2535.0   Max.   :146.00   Max.   :2554   Max.   :458.0   Max.   :223.00   Max.   :264.00   Max.   :878.0  
   batting_so       baserun_sb    baserun_cs    pitching_h     pitching_hr     pitching_bb      pitching_so     
 Min.   :   0.0   Min.   :  0   Min.   :  0   Min.   : 1137   Min.   :  0.0   Min.   :   0.0   Min.   :    0.0  
 1st Qu.: 545.0   1st Qu.: 67   1st Qu.: 42   1st Qu.: 1419   1st Qu.: 50.0   1st Qu.: 476.0   1st Qu.:  611.8  
 Median : 732.0   Median :106   Median : 57   Median : 1518   Median :107.0   Median : 536.5   Median :  803.0  
 Mean   : 728.2   Mean   :136   Mean   : 76   Mean   : 1779   Mean   :105.7   Mean   : 553.0   Mean   :  810.5  
 3rd Qu.: 925.0   3rd Qu.:170   3rd Qu.: 90   3rd Qu.: 1682   3rd Qu.:150.0   3rd Qu.: 611.0   3rd Qu.:  957.2  
 Max.   :1399.0   Max.   :697   Max.   :201   Max.   :30132   Max.   :343.0   Max.   :3645.0   Max.   :19278.0  
   fielding_e      fielding_dp    batting_hbp_bi   
 Min.   :  65.0   Min.   : 52.0   Min.   :0.00000  
 1st Qu.: 127.0   1st Qu.:126.0   1st Qu.:0.00000  
 Median : 159.0   Median :145.0   Median :0.00000  
 Mean   : 246.5   Mean   :141.9   Mean   :0.08392  
 3rd Qu.: 249.2   3rd Qu.:162.0   3rd Qu.:0.00000  
 Max.   :1898.0   Max.   :228.0   Max.   :1.00000  

let’s test a model to establish a baseline

mse(stepwise_base_model)
[1] 157.695
mse(base_model)
[1] 157.4534
mse(robust_base_model)
[1] 158.2798

Let’s use caret preprocess function to help us fix the issues we found while exploring the data.

First, we will use box-cox to normalize the data.

First we start with a quick ana Let’s do a quick analysis to understand the distribution of NA values accross our dataset. Let’s sort the fields with most NAs from high to low.

#let check for NAs in the data
#Counting the number of NAs per column and check the percentage of NAs per column
NAPerc <- sapply(moneyball, function(x) (sum(is.na(x))/length(x))*100) %>%
  data.frame()
NAPerc$Column <- rownames(NAPerc)
colnames(NAPerc) <- c("NA_Perc", "Col_Name")
subset(NAPerc,NA_Perc > 0) %>% arrange(desc(NA_Perc))
matrixplot(moneyball)

Click in a column to sort by the corresponding variable.
To regain use of the VIM GUI and the R console, click outside the plot region.

It’s clear that TEAM_BATTING_HBP is going to be a problematic column with 92% of the data missing. Before we start the imputation, let’s try to understand why we have missing data.

There are two types of missing data

Let’s use the mice package to help us understant how all the NAs behave in the data. mice provides a handy function called md.pattern that allows one to understand the pattern of missing data. Hopefully by looking at the pattern, we can have an idea on why the data could be missing.

md.pattern(moneyball) %>% data.frame()

Here is a great article from Rblogger that discusses the package MICE.

Let the Inputation begin

cor.ci(moneyball, method="spearman")
Call:corCi(x = x, keys = keys, n.iter = n.iter, p = p, overlap = overlap, 
    poly = poly, method = method, plot = plot, minlength = minlength)

 Coefficients and bootstrapped confidence intervals 
                 INDEX TARGE TEAM_BATTING_H TEAM_BATTING_2 TEAM_BATTING_3 TEAM_BATTING_HR TEAM_BATTING_B
INDEX             1.00                                                                                  
TARGET_WINS      -0.01  1.00                                                                            
TEAM_BATTING_H    0.00  0.37  1.00                                                                      
TEAM_BATTING_2B   0.02  0.24  0.60           1.00                                                       
TEAM_BATTING_3B   0.00  0.12  0.33          -0.16           1.00                                        
TEAM_BATTING_HR   0.05  0.16  0.07           0.44          -0.68           1.00                         
TEAM_BATTING_BB  -0.04  0.23  0.07           0.27          -0.28           0.49            1.00         
TEAM_BATTING_SO   0.09 -0.08 -0.40           0.17          -0.72           0.73            0.26         
TEAM_BASERUN_SB   0.06  0.11  0.00          -0.16           0.36          -0.42           -0.15         
TEAM_BASERUN_CS   0.02 -0.01  0.02          -0.02           0.20          -0.37           -0.17         
TEAM_BATTING_HBP  0.06  0.04 -0.03           0.02          -0.17           0.08            0.01         
TEAM_PITCHING_H  -0.01  0.21  0.75           0.28           0.54          -0.30           -0.14         
TEAM_PITCHING_HR  0.05  0.17  0.11           0.46          -0.65           0.98            0.46         
TEAM_PITCHING_BB -0.04  0.21  0.15           0.22          -0.10           0.28            0.87         
TEAM_PITCHING_SO  0.09 -0.09 -0.37           0.11          -0.60           0.57            0.12         
TEAM_FIELDING_E  -0.03 -0.12  0.11          -0.38           0.74          -0.81           -0.43         
TEAM_FIELDING_DP  0.01 -0.05  0.18           0.25          -0.25           0.39            0.32         
                 TEAM_BATTING_S TEAM_BASERUN_S TEAM_BASERUN_C TEAM_BATTING_HB TEAM_PITCHING_H
INDEX                                                                                        
TARGET_WINS                                                                                  
TEAM_BATTING_H                                                                               
TEAM_BATTING_2B                                                                              
TEAM_BATTING_3B                                                                              
TEAM_BATTING_HR                                                                              
TEAM_BATTING_BB                                                                              
TEAM_BATTING_SO   1.00                                                                       
TEAM_BASERUN_SB  -0.11           1.00                                                        
TEAM_BASERUN_CS  -0.17           0.67           1.00                                         
TEAM_BATTING_HBP  0.17          -0.03          -0.06           1.00                          
TEAM_PITCHING_H  -0.60           0.14           0.02          -0.02            1.00          
TEAM_PITCHING_HR  0.69          -0.41          -0.36           0.08           -0.21          
TEAM_PITCHING_BB  0.06          -0.02          -0.13           0.01            0.14          
TEAM_PITCHING_SO  0.90          -0.06          -0.16           0.18           -0.37          
TEAM_FIELDING_E  -0.74           0.36           0.21           0.07            0.47          
TEAM_FIELDING_DP  0.09          -0.42          -0.14          -0.07            0.04          
                 TEAM_PITCHING_HR TEAM_PITCHING_B TEAM_PITCHING_S
INDEX                                                            
TARGET_WINS                                                      
TEAM_BATTING_H                                                   
TEAM_BATTING_2B                                                  
TEAM_BATTING_3B                                                  
TEAM_BATTING_HR                                                  
TEAM_BATTING_BB                                                  
TEAM_BATTING_SO                                                  
TEAM_BASERUN_SB                                                  
TEAM_BASERUN_CS                                                  
TEAM_BATTING_HBP                                                 
TEAM_PITCHING_H                                                  
TEAM_PITCHING_HR  1.00                                           
TEAM_PITCHING_BB  0.32             1.00                          
TEAM_PITCHING_SO  0.59             0.04            1.00          
TEAM_FIELDING_E  -0.77            -0.19           -0.56          
TEAM_FIELDING_DP  0.39             0.27            0.01          
                 TEAM_FIELDING_E TEAM_FIELDING_D
TEAM_FIELDING_E   1.00                          
TEAM_FIELDING_DP -0.37            1.00          

 scale correlations and bootstrapped confidence intervals 
                                 lower.emp lower.norm estimate upper.norm upper.emp    p
INDEX-TARGE                          -0.05      -0.05    -0.01       0.03      0.03 0.55
INDEX-TEAM_BATTING_H                 -0.05      -0.04     0.00       0.04      0.04 0.97
INDEX-TEAM_BATTING_2                 -0.03      -0.03     0.02       0.06      0.06 0.41
INDEX-TEAM_BATTING_3                 -0.05      -0.05     0.00       0.05      0.04 1.00
INDEX-TEAM_BATTING_HR                 0.01       0.01     0.05       0.09      0.10 0.01
INDEX-TEAM_BATTING_B                 -0.08      -0.08    -0.04       0.00      0.00 0.07
INDEX-TEAM_BATTING_S                  0.05       0.05     0.09       0.13      0.13 0.00
INDEX-TEAM_BASERUN_S                  0.03       0.02     0.06       0.11      0.11 0.00
INDEX-TEAM_BASERUN_C                 -0.03      -0.03     0.02       0.08      0.08 0.39
INDEX-TEAM_BATTING_HB                -0.09      -0.09     0.06       0.19      0.20 0.50
INDEX-TEAM_PITCHING_H                -0.06      -0.06    -0.01       0.03      0.03 0.60
INDEX-TEAM_PITCHING_HR                0.02       0.01     0.05       0.09      0.09 0.01
INDEX-TEAM_PITCHING_B                -0.08      -0.08    -0.04       0.00      0.00 0.06
INDEX-TEAM_PITCHING_S                 0.05       0.05     0.09       0.13      0.12 0.00
INDEX-TEAM_FIELDING_E                -0.07      -0.07    -0.03       0.01      0.00 0.10
INDEX-TEAM_FIELDING_D                -0.03      -0.03     0.01       0.05      0.05 0.48
TARGE-TEAM_BATTING_H                  0.33       0.33     0.37       0.40      0.41 0.00
TARGE-TEAM_BATTING_2                  0.20       0.20     0.24       0.27      0.27 0.00
TARGE-TEAM_BATTING_3                  0.09       0.09     0.12       0.17      0.16 0.00
TARGE-TEAM_BATTING_HR                 0.11       0.11     0.16       0.20      0.19 0.00
TARGE-TEAM_BATTING_B                  0.18       0.18     0.23       0.27      0.27 0.00
TARGE-TEAM_BATTING_S                 -0.13      -0.12    -0.08      -0.03     -0.03 0.00
TARGE-TEAM_BASERUN_S                  0.07       0.07     0.11       0.16      0.15 0.00
TARGE-TEAM_BASERUN_C                 -0.05      -0.05    -0.01       0.04      0.03 0.70
TARGE-TEAM_BATTING_HB                -0.12      -0.13     0.04       0.19      0.21 0.70
TARGE-TEAM_PITCHING_H                 0.17       0.17     0.21       0.26      0.26 0.00
TARGE-TEAM_PITCHING_HR                0.12       0.12     0.17       0.20      0.20 0.00
TARGE-TEAM_PITCHING_B                 0.16       0.17     0.21       0.25      0.25 0.00
TARGE-TEAM_PITCHING_S                -0.13      -0.14    -0.09      -0.05     -0.05 0.00
TARGE-TEAM_FIELDING_E                -0.16      -0.17    -0.12      -0.07     -0.07 0.00
TARGE-TEAM_FIELDING_D                -0.09      -0.10    -0.05      -0.01     -0.01 0.02
TEAM_BATTING_H-TEAM_BATTING_2         0.57       0.57     0.60       0.62      0.62 0.00
TEAM_BATTING_H-TEAM_BATTING_3         0.30       0.29     0.33       0.36      0.36 0.00
TEAM_BATTING_H-TEAM_BATTING_HR        0.02       0.02     0.07       0.11      0.11 0.00
TEAM_BATTING_H-TEAM_BATTING_B         0.02       0.03     0.07       0.12      0.12 0.00
TEAM_BATTING_H-TEAM_BATTING_S        -0.44      -0.44    -0.40      -0.35     -0.35 0.00
TEAM_BATTING_H-TEAM_BASERUN_S        -0.04      -0.04     0.00       0.05      0.05 0.77
TEAM_BATTING_H-TEAM_BASERUN_C        -0.03      -0.04     0.02       0.08      0.07 0.53
TEAM_BATTING_H-TEAM_BATTING_HB       -0.16      -0.18    -0.03       0.11      0.11 0.65
TEAM_BATTING_H-TEAM_PITCHING_H        0.72       0.72     0.75       0.78      0.78 0.00
TEAM_BATTING_H-TEAM_PITCHING_HR       0.06       0.06     0.11       0.15      0.15 0.00
TEAM_BATTING_H-TEAM_PITCHING_B        0.11       0.11     0.15       0.20      0.19 0.00
TEAM_BATTING_H-TEAM_PITCHING_S       -0.41      -0.41    -0.37      -0.33     -0.32 0.00
TEAM_BATTING_H-TEAM_FIELDING_E        0.07       0.07     0.11       0.15      0.15 0.00
TEAM_BATTING_H-TEAM_FIELDING_D        0.13       0.13     0.18       0.22      0.22 0.00
TEAM_BATTING_2-TEAM_BATTING_3        -0.19      -0.19    -0.16      -0.12     -0.12 0.00
TEAM_BATTING_2-TEAM_BATTING_HR        0.40       0.41     0.44       0.48      0.48 0.00
TEAM_BATTING_2-TEAM_BATTING_B         0.23       0.23     0.27       0.31      0.31 0.00
TEAM_BATTING_2-TEAM_BATTING_S         0.12       0.12     0.17       0.21      0.22 0.00
TEAM_BATTING_2-TEAM_BASERUN_S        -0.21      -0.20    -0.16      -0.12     -0.12 0.00
TEAM_BATTING_2-TEAM_BASERUN_C        -0.09      -0.08    -0.02       0.03      0.03 0.41
TEAM_BATTING_2-TEAM_BATTING_HB       -0.10      -0.12     0.02       0.15      0.16 0.80
TEAM_BATTING_2-TEAM_PITCHING_H        0.24       0.24     0.28       0.32      0.32 0.00
TEAM_BATTING_2-TEAM_PITCHING_HR       0.42       0.42     0.46       0.49      0.49 0.00
TEAM_BATTING_2-TEAM_PITCHING_B        0.18       0.18     0.22       0.26      0.26 0.00
TEAM_BATTING_2-TEAM_PITCHING_S        0.07       0.07     0.11       0.15      0.15 0.00
TEAM_BATTING_2-TEAM_FIELDING_E       -0.41      -0.41    -0.38      -0.34     -0.34 0.00
TEAM_BATTING_2-TEAM_FIELDING_D        0.21       0.21     0.25       0.29      0.29 0.00
TEAM_BATTING_3-TEAM_BATTING_HR       -0.70      -0.70    -0.68      -0.65     -0.65 0.00
TEAM_BATTING_3-TEAM_BATTING_B        -0.33      -0.33    -0.28      -0.25     -0.25 0.00
TEAM_BATTING_3-TEAM_BATTING_S        -0.74      -0.74    -0.72      -0.70     -0.71 0.00
TEAM_BATTING_3-TEAM_BASERUN_S         0.31       0.31     0.36       0.40      0.39 0.00
TEAM_BATTING_3-TEAM_BASERUN_C         0.14       0.14     0.20       0.25      0.24 0.00
TEAM_BATTING_3-TEAM_BATTING_HB       -0.33      -0.32    -0.17      -0.05     -0.05 0.01
TEAM_BATTING_3-TEAM_PITCHING_H        0.50       0.50     0.54       0.57      0.57 0.00
TEAM_BATTING_3-TEAM_PITCHING_HR      -0.67      -0.67    -0.65      -0.62     -0.62 0.00
TEAM_BATTING_3-TEAM_PITCHING_B       -0.14      -0.14    -0.10      -0.06     -0.06 0.00
TEAM_BATTING_3-TEAM_PITCHING_S       -0.63      -0.63    -0.60      -0.57     -0.57 0.00
TEAM_BATTING_3-TEAM_FIELDING_E        0.72       0.72     0.74       0.76      0.76 0.00
TEAM_BATTING_3-TEAM_FIELDING_D       -0.30      -0.30    -0.25      -0.21     -0.21 0.00
TEAM_BATTING_HR-TEAM_BATTING_B        0.45       0.46     0.49       0.53      0.53 0.00
TEAM_BATTING_HR-TEAM_BATTING_S        0.71       0.71     0.73       0.75      0.75 0.00
TEAM_BATTING_HR-TEAM_BASERUN_S       -0.46      -0.46    -0.42      -0.38     -0.39 0.00
TEAM_BATTING_HR-TEAM_BASERUN_C       -0.42      -0.42    -0.37      -0.33     -0.33 0.00
TEAM_BATTING_HR-TEAM_BATTING_HB      -0.07      -0.07     0.08       0.23      0.23 0.30
TEAM_BATTING_HR-TEAM_PITCHING_H      -0.34      -0.35    -0.30      -0.26     -0.26 0.00
TEAM_BATTING_HR-TEAM_PITCHING_HR      0.97       0.97     0.98       0.98      0.98 0.00
TEAM_BATTING_HR-TEAM_PITCHING_B       0.25       0.25     0.28       0.32      0.32 0.00
TEAM_BATTING_HR-TEAM_PITCHING_S       0.54       0.53     0.57       0.61      0.61 0.00
TEAM_BATTING_HR-TEAM_FIELDING_E      -0.82      -0.82    -0.81      -0.80     -0.80 0.00
TEAM_BATTING_HR-TEAM_FIELDING_D       0.34       0.34     0.39       0.43      0.43 0.00
TEAM_BATTING_B-TEAM_BATTING_S         0.22       0.22     0.26       0.30      0.30 0.00
TEAM_BATTING_B-TEAM_BASERUN_S        -0.19      -0.20    -0.15      -0.11     -0.11 0.00
TEAM_BATTING_B-TEAM_BASERUN_C        -0.22      -0.22    -0.17      -0.12     -0.12 0.00
TEAM_BATTING_B-TEAM_BATTING_HB       -0.15      -0.15     0.01       0.16      0.16 0.96
TEAM_BATTING_B-TEAM_PITCHING_H       -0.19      -0.20    -0.14      -0.10     -0.10 0.00
TEAM_BATTING_B-TEAM_PITCHING_HR       0.43       0.43     0.46       0.50      0.50 0.00
TEAM_BATTING_B-TEAM_PITCHING_B        0.85       0.85     0.87       0.89      0.89 0.00
TEAM_BATTING_B-TEAM_PITCHING_S        0.08       0.07     0.12       0.16      0.15 0.00
TEAM_BATTING_B-TEAM_FIELDING_E       -0.46      -0.46    -0.43      -0.39     -0.39 0.00
TEAM_BATTING_B-TEAM_FIELDING_D        0.28       0.27     0.32       0.36      0.36 0.00
TEAM_BATTING_S-TEAM_BASERUN_S        -0.16      -0.16    -0.11      -0.07     -0.08 0.00
TEAM_BATTING_S-TEAM_BASERUN_C        -0.21      -0.22    -0.17      -0.13     -0.13 0.00
TEAM_BATTING_S-TEAM_BATTING_HB        0.01       0.03     0.17       0.31      0.32 0.02
TEAM_BATTING_S-TEAM_PITCHING_H       -0.63      -0.63    -0.60      -0.57     -0.57 0.00
TEAM_BATTING_S-TEAM_PITCHING_HR       0.67       0.67     0.69       0.71      0.71 0.00
TEAM_BATTING_S-TEAM_PITCHING_B        0.02       0.02     0.06       0.10      0.10 0.00
TEAM_BATTING_S-TEAM_PITCHING_S        0.88       0.88     0.90       0.92      0.92 0.00
TEAM_BATTING_S-TEAM_FIELDING_E       -0.76      -0.76    -0.74      -0.72     -0.72 0.00
TEAM_BATTING_S-TEAM_FIELDING_D        0.05       0.05     0.09       0.14      0.15 0.00
TEAM_BASERUN_S-TEAM_BASERUN_C         0.65       0.64     0.67       0.70      0.70 0.00
TEAM_BASERUN_S-TEAM_BATTING_HB       -0.18      -0.18    -0.03       0.12      0.10 0.67
TEAM_BASERUN_S-TEAM_PITCHING_H        0.10       0.10     0.14       0.19      0.18 0.00
TEAM_BASERUN_S-TEAM_PITCHING_HR      -0.44      -0.44    -0.41      -0.37     -0.37 0.00
TEAM_BASERUN_S-TEAM_PITCHING_B       -0.07      -0.06    -0.02       0.03      0.03 0.50
TEAM_BASERUN_S-TEAM_PITCHING_S       -0.10      -0.10    -0.06      -0.01     -0.01 0.01
TEAM_BASERUN_S-TEAM_FIELDING_E        0.31       0.31     0.36       0.40      0.40 0.00
TEAM_BASERUN_S-TEAM_FIELDING_D       -0.46      -0.46    -0.42      -0.37     -0.38 0.00
TEAM_BASERUN_C-TEAM_BATTING_HB       -0.20      -0.19    -0.06       0.08      0.05 0.39
TEAM_BASERUN_C-TEAM_PITCHING_H       -0.03      -0.03     0.02       0.07      0.07 0.52
TEAM_BASERUN_C-TEAM_PITCHING_HR      -0.41      -0.42    -0.36      -0.32     -0.32 0.00
TEAM_BASERUN_C-TEAM_PITCHING_B       -0.17      -0.18    -0.13      -0.08     -0.09 0.00
TEAM_BASERUN_C-TEAM_PITCHING_S       -0.21      -0.21    -0.16      -0.11     -0.11 0.00
TEAM_BASERUN_C-TEAM_FIELDING_E        0.16       0.16     0.21       0.26      0.26 0.00
TEAM_BASERUN_C-TEAM_FIELDING_D       -0.19      -0.19    -0.14      -0.08     -0.07 0.00
TEAM_BATTING_HB-TEAM_PITCHING_H      -0.16      -0.17    -0.02       0.12      0.11 0.69
TEAM_BATTING_HB-TEAM_PITCHING_HR     -0.07      -0.07     0.08       0.23      0.23 0.29
TEAM_BATTING_HB-TEAM_PITCHING_B      -0.15      -0.15     0.01       0.16      0.16 0.95
TEAM_BATTING_HB-TEAM_PITCHING_S       0.01       0.03     0.18       0.31      0.32 0.02
TEAM_BATTING_HB-TEAM_FIELDING_E      -0.04      -0.05     0.07       0.21      0.21 0.21
TEAM_BATTING_HB-TEAM_FIELDING_D      -0.18      -0.20    -0.07       0.08      0.08 0.38
TEAM_PITCHING_H-TEAM_PITCHING_HR     -0.25      -0.25    -0.21      -0.17     -0.17 0.00
TEAM_PITCHING_H-TEAM_PITCHING_B       0.09       0.09     0.14       0.19      0.18 0.00
TEAM_PITCHING_H-TEAM_PITCHING_S      -0.41      -0.41    -0.37      -0.33     -0.33 0.00
TEAM_PITCHING_H-TEAM_FIELDING_E       0.42       0.43     0.47       0.51      0.50 0.00
TEAM_PITCHING_H-TEAM_FIELDING_D      -0.02      -0.02     0.04       0.08      0.08 0.22
TEAM_PITCHING_HR-TEAM_PITCHING_B      0.28       0.28     0.32       0.36      0.36 0.00
TEAM_PITCHING_HR-TEAM_PITCHING_S      0.55       0.55     0.59       0.62      0.62 0.00
TEAM_PITCHING_HR-TEAM_FIELDING_E     -0.78      -0.78    -0.77      -0.75     -0.75 0.00
TEAM_PITCHING_HR-TEAM_FIELDING_D      0.34       0.34     0.39       0.44      0.43 0.00
TEAM_PITCHING_B-TEAM_PITCHING_S       0.00       0.00     0.04       0.09      0.08 0.03
TEAM_PITCHING_B-TEAM_FIELDING_E      -0.23      -0.23    -0.19      -0.15     -0.16 0.00
TEAM_PITCHING_B-TEAM_FIELDING_D       0.22       0.22     0.27       0.31      0.30 0.00
TEAM_PITCHING_S-TEAM_FIELDING_E      -0.60      -0.60    -0.56      -0.52     -0.52 0.00
TEAM_PITCHING_S-TEAM_FIELDING_D      -0.03      -0.03     0.01       0.06      0.06 0.49
TEAM_FIELDING_E-TEAM_FIELDING_D      -0.41      -0.41    -0.37      -0.33     -0.33 0.00

The Caret package offers the findcorrelation(), which takes the correlation matrix as an input and finds the fields causing multicollinearity based on a threshold, the cutoff parameter. It in turns returns a vector with values that would need to be removed from our dataset due to correlation. ## Reference

LS0tCnRpdGxlOiAiTW9uZXliYWxsIgphdXRob3I6CiAgLSBKb3JnZSBGZXJuYW5kZXMKICAtIE1TRFMgNDExCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCICVZJylgIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpMaXN0IG9mIFBhY2thZ2VzIHVzZWQ7ICAKIC0gY2FyZXQgIAogLSBjb3JycGxvdCAgCiAtIGRwbHlyICAKIC0gbWlzc0ZvcmVzdCAgCmBgYHtyIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkoZTEwNzEpICMgdG8gdW5kZXJzdGFuZCBza2V3bmVzcwpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHN0cmluZ3IpICMgVXNlZCB0byByZW5hbWUgdGhlIGNvbHVtbnMgYnkgcmVtb3ZpbmcgdGhlIHdvcmQgdGVhbSBmcm9tIHRoZSBjb2x1bW4gaGVhZGVyCmxpYnJhcnkoVklNKSAjIFRvIHVuZGVyc3RhbmQgTkFzCmxpYnJhcnkoY2FyZXQpCmxpYnJhcnkoIk1BU1MiKSAjIHRvIHVzZSBmb3Igcm9idXN0IExpbmVhciBSZWdyZXNzaW9uLgpgYGAKCgpgYGB7cn0KIyBicm93c2UgdG8gdGhlIGRhdGEKbW9uZXliYWxsID0gcmVhZC5jc3YoJy9Vc2Vycy9sZWdzX2pvcmdlL0RvY3VtZW50cy9EYXRhIFNjaWVuY2UgUHJvamVjdHMvTVNEU19Ob3J0aHdlc3Rlcm4vTVNEUyA0MTEvVW5pdCAwMSBNb25leWJhbGwgQmFzZWJhbGwgUHJvYmxlbS9EYXRhL21vbmV5YmFsbC5jc3YnLCBoZWFkZXIgPSBUKQpjb2xuYW1lcyhtb25leWJhbGwpIDwtIHN0cl9yZXBsYWNlX2FsbChjb2xuYW1lcyhtb25leWJhbGwpLCJURUFNXyIsIiIpICU+JSAKICB0b2xvd2VyKCkgIyBGaXhpbmcgY29sdW1uIG5hbWVzCmBgYAoKCgoKIyMgRGF0YSBFeHBsb3JhdGlvbgoKIyMjIFN0ZXBzCiAxLiBPdXRsaWVycy9pbmZsdWVuY2lhbCBQb2ludHMgaW4gSW5kZXBlbmRlbnQgYW5kIERlcGVuZGVudCB2YXJpYWJsZXMKIDIuIEhvbW9nZW5laXR5CiAzLiBOb3JtYWxpdHkgb2YgRGVwZW5kZW50IHZhcmlhYmxlCiA0LiBaZXJvIHRyb3VibGUgb2YgRGVwZW5kZW50IHZhcmlhYmxlCiA1LiBDb2xsaW5lYXJpdHkgb2YgSW5kZXBlbmRlbnQgdmFyaWFibGVzIAogNi4gUmVsYXRpb25wcyBCZXR3ZWVuIEluZGVwZW5kZW50IGFuZCBEZXBlbmRlbnQgdmFyaWFibGVzIAogNy4gSW50ZXJhY3Rpb25zIAogOC4gSW5kZXBlbmRlbmNlIG9mIERlcGVuZGVudCB2YXJpYWJsZQogCiMjIyBTdGVwIDE6IENhbiB3ZSBmaW5kIG91dGxpZXJzIGluIG91ciBJbmRlcGVuZGVudCBhbmQgRGVwZW5kZW50IHZhcmlhYmxlcz8gCgpPdXRsaWVycyBjYW4gY2F1c2Ugb3VyIG1vZGVsIHRvIHByb2R1Y2UgdGhlIHdyb25nIG91dHB1dCBieSBpbmZsdWVuY2luZyBpdHMgZml0LiAKQ3JlYXRpbmcgYm94cGxvdHMgd2lsbCBhaWQgaW4gaWRlbnRpZnlpbmcgdGhvc2Ugb3V0bGllcnMuCldlIGNhbiBhbHNvIHVzZSB0aGUgY2xldmVsYW5kIGRvdHBsb3QgdG8gdW5kZXJzdGFuZCB0aGUgb3V0bGllcnMgYmV0dGVyLiBUaGlzIHRlY2huaXF1ZSB1c2VzIHRoZSByb3cgbnVtYmVyIGFnYWluc3QgYWN0dWFsIHZhbHVlIHRvIHF1aWNrbHkgcG9pbnQgb3V0IGFueSBwYXR0ZXJucyBvZiBvdXRsaWVycy4gVGhpcyBwbG90IHdpbGwgZWFzaWxseSBhbGxvdyB1cyB0byBjaGVjayB0aGUgcmF3IGRhdGEgZm9yIGVycm9ycyBzdWNoIGFzIHR5cG9zIGR1cmluZyB0aGUgZGF0YSBjb2xsZWN0aW9uIHBoYXNlLiBQb2ludHMgb24gdGhlIGZhciByaWdodCBzaWRlLCBvciBvbiB0aGUgZmFyIGxlZnQgc2lkZSwgYXJlIG9ic2VydmVkIHZhbHVlcyB0aGF0IGFyZSBjb25zaWRlcmFibHkgbGFyZ2VyLCBvciBzbWFsbGVyLCB0aGFuIHRoZSBtYWpvcml0eSBvZiB0aGUgb2JzZXJ2YXRpb25zLCBhbmQgcmVxdWlyZSBmdXJ0aGVyIGludmVzdGlnYXRpb24uIFdoZW4gd2UgdXNlIHRoaXMgY2hhcnQsIHRvZ2V0aGVyIHdpdGggdGhlIGJveCBwbG90IGFuZCBoaXN0b2dyYW0sIHdlIGNhbiBlYXNpbHkgaWRlbnRpZnkgcGF0dGVybnMgYXQgdG8gd2hlcmUgaW4gdGhlIGRhdGEgd2UncmUgc2VlaW5nIG91dGxpZXJzLgoKYGBge3J9CnBhcihtZnJvdyA9IGMoMSwgMykpCmkgPSAyCndoaWxlIChpICVpbiUgYygyOjE3KSkgewogCnBsb3QobW9uZXliYWxsWyxpXSwgbW9uZXliYWxsJGluZGV4LCB4bGFiID0gY29sbmFtZXMobW9uZXliYWxsKVtpXSAsIHlsYWIgPSAiSW5kZXgiLCBtYWluID0gcGFzdGUoImNsZXZlbGFuZCBkb3RwbG90IG9mICIsY29sbmFtZXMobW9uZXliYWxsKVtpXSkpCgpib3hwbG90KG1vbmV5YmFsbFssaV0sIGNvbCA9ICIjQTcxOTMwIiwgbWFpbiA9IHBhc3RlKCJCb3hwbG90IG9mICIsY29sbmFtZXMobW9uZXliYWxsKVtpXSkpCgpoaXN0KAogIG1vbmV5YmFsbFssaV0sCiAgY29sID0gIiNBNzE5MzAiLAogIHhsYWIgPSBjb2xuYW1lcyhtb25leWJhbGwpW2ldLAogIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mICIsY29sbmFtZXMobW9uZXliYWxsKVtpXSkKKQogIGkgPSBpICsgMQp9CgpgYGAKCgoKSXQgbG9va3MgbGlrZSB0aGUgb3V0bGllcnMgYXJlIGxlZ2l0bWF0ZSBhbmQgd2Ugd2lsbCB0cnkgdHdvIHRlY2huaXF1ZXMgdG8gZGVhbCB3aXRoIHRoZW07ICAKMS4gVXNlIFJvYnVzdCBsaW5lYXIgUmVncmVzc2lvbiAgCjIuIFVzZSBTcGF0aWFsIFNpZ24gdHJhbnNmb3JtYXRpb24gYWZ0ZXIgc2NhbGluZyBhbmQgY2VudGVyaW5nIHRoZSBkYXRhLiAgCgpOb3cgdGhhdCBzdGVwIG9uZSBpcyBkb25lLCBsZXQncyBsb29rIGF0IHN0ZXAgMi4KCiMjIyBTdGVwIDI6IEFyZSB0aGUgZGF0YSBub3JtYWxseSBkaXN0cmlidXRlZD8KCkZyb20gdGhlIGhpc3RvcmdyYW0gYWJvdmUgd2UgY2FuIGNsZWFybHkgc2VlIHRoYXQgdGhlIGRhdGEgaXMgbm90IG5vcm1hbCwgd2l0aCB0aGUgZXhjZXB0aW9uIG9mIHNvbWUgdGhhdCBzZWVtcyB0byBzb3J0IG9mIGZvbGxvdyBhIG5vcm1hbCBkaXN0cmlidXRpb24uCkxldCdzIHVzZSBRUS1wbG90IHRvIHRlc3QgZWFjaCBjb2x1bW4gZm9yIG5vcm1hbGl0eSwgd2hpbGUgYWRkaW5nIGEgaGlzdG9ncmFtIGFuZCBhIFNrZXduZXNzIG51bWJlci4gICAKIC0gSWYgc2tld25lc3MgaXMgbGVzcyB0aGFuIOKIkjEgb3IgZ3JlYXRlciB0aGFuICsxLCB0aGUgZGlzdHJpYnV0aW9uIGlzIGhpZ2hseSBza2V3ZWQuICAKIC0gSWYgc2tld25lc3MgaXMgYmV0d2VlbiDiiJIxIGFuZCDiiJLCvSBvciBiZXR3ZWVuICvCvSBhbmQgKzEsIHRoZSBkaXN0cmlidXRpb24gaXMgbW9kZXJhdGVseSBza2V3ZWQuICAKIC0gSWYgc2tld25lc3MgaXMgYmV0d2VlbiDiiJLCvSBhbmQgK8K9LCB0aGUgZGlzdHJpYnV0aW9uIGlzIGFwcHJveGltYXRlbHkgc3ltbWV0cmljLiAgCmBgYHtyfQpwYXIobWZyb3cgPSBjKDIsIDIpKQppID0gMgp3aGlsZSAoaSAlaW4lIGMoMjoxNykpIHsKICBxcW5vcm0obW9uZXliYWxsWyxpXSwgbWFpbiA9IHBhc3RlKCJRUS1QbG90IG9mICIsY29sbmFtZXMobW9uZXliYWxsKVtpXSkpO3FxbGluZShtb25leWJhbGxbLGldLCBjb2wgPSAyKQogIAogIGhpc3QoCiAgbW9uZXliYWxsWyxpXSwKICBjb2wgPSAiI0E3MTkzMCIsCiAgeGxhYiA9IGNvbG5hbWVzKG1vbmV5YmFsbClbaV0sCiAgbWFpbiA9IHBhc3RlMCgiU2tld25lc3MgPSAiLHNrZXduZXNzKG1vbmV5YmFsbFssaV0pKQopCiAgCiAgaSA9IGkgKyAxCiAgCn0KCmBgYAoKV2Ugd291bGQgbmVlZCB0byB0cnkgY2VydGFpbiB0cmFuc2Zvcm1hdGlvbiB0byBjb3JyZWN0IGZvciBTa2V3bmVzcywgd2l0aCBCb3gtQ294IGJlaW5nIHRoZSBudW1iZXIgb25lIGNob2ljZS4KCiMjIyBTdGVwIDQ6IEFyZSB0aGVyZSBsb3RzIG9mIE5BcyBpbiB0aGUgZGF0YT8KClIgZ2l2ZXMgdXMgYSBsb3Qgb2Ygd2F5cyB0byB1bmRlcnN0YW5kIHRoZSBkaXN0cmlidXRpb24gb2YgYE51bGxzYCB3aXRoaW4gdGhlIGRhdGEuIExldCdzIGZpcnN0IHRyeSB0byBjYWxjdWxhdGUgdGhlIHBlcmNlbnRhZ2Ugb2YgTnVsbCB2YWx1ZXMgdG8gdGhlIHRvdGFsIG51bWJlciBvZiBvYnNlcnZhdGlvbi4KYGBge3J9Ck5BUGVyYyA8LQogIHNhcHBseShtb25leWJhbGwsIGZ1bmN0aW9uKHgpCiAgICAoc3VtKGlzLm5hKHgpKSAvIGxlbmd0aCh4KSkgKiAxMDApICU+JQogIGRhdGEuZnJhbWUoKQpOQVBlcmMkQ29sdW1uIDwtIHJvd25hbWVzKE5BUGVyYykKY29sbmFtZXMoTkFQZXJjKSA8LSBjKCJOQV9QZXJjIiwgIkNvbF9OYW1lIikKCiMgVHJ5aW5nIHRvIHVuZGVyc3RhbmQgdGhlIHBlcmNlbnRhZ2Ugb2YgTkFzIHBlciBDb2x1bW4KTkFfY29sIDwtIHN1YnNldChOQVBlcmMsIE5BX1BlcmMgPiAwKSAlPiUgYXJyYW5nZShkZXNjKE5BX1BlcmMpKQpOQV9jb2wKTkFfc3Vic2V0IDwtIG1vbmV5YmFsbFssIGMoTkFfY29sJENvbF9OYW1lKV0KbWF0cml4cGxvdChOQV9zdWJzZXQsIGxhYmVscyA9IFRSVUUsIGludGVyYWN0aXZlID0gVFJVRSkKYGBgCgpMZXQncyBsb29rIGF0IHRoZSBwYXR0ZXJuIG9mIG1pc3NpbmcgZGF0YSB0byB0cnkgdG8gZ2V0IG1vcmUgaW5zaWdodHMuIEl0J3MgY2xlYXIgdGhhdCBURUFNX0JBVFRJTkdfSEJQIGlzIGdvaW5nIHRvIGJlIGEgcHJvYmxlbWF0aWMgY29sdW1uIHdpdGggOTIlIG9mIHRoZSBkYXRhIG1pc3NpbmcuCkJlZm9yZSB3ZSBzdGFydCB0aGUgaW1wdXRhdGlvbiwgbGV0J3MgdHJ5IHRvIHVuZGVyc3RhbmQgd2h5IHdlIGhhdmUgbWlzc2luZyBkYXRhLiAKCioqVGhlcmUgYXJlIHR3byB0eXBlcyBvZiBtaXNzaW5nIGRhdGEqKiAgCgogLSAqTUNBUio6IG1pc3NpbmcgY29tcGxldGVseSBhdCByYW5kb20uIFRoaXMgaXMgdGhlIGRlc2lyYWJsZSBzY2VuYXJpbyBpbiBjYXNlIG9mIG1pc3NpbmcgZGF0YS4gIAogLSAqTU5BUio6IG1pc3Npbmcgbm90IGF0IHJhbmRvbS4gTWlzc2luZyBub3QgYXQgcmFuZG9tIGRhdGEgaXMgYSBtb3JlIHNlcmlvdXMgaXNzdWUgYW5kIGluIHRoaXMgY2FzZSBpdCBtaWdodCBiZSB3aXNlIHRvIGNoZWNrIHRoZSBkYXRhIGdhdGhlcmluZyBwcm9jZXNzIGZ1cnRoZXIgYW5kIHRyeSB0byB1bmRlcnN0YW5kIHdoeSB0aGUgaW5mb3JtYXRpb24gaXMgbWlzc2luZy4gRm9yIGluc3RhbmNlLCBpZiBtb3N0IG9mIHRoZSBwZW9wbGUgaW4gYSBzdXJ2ZXkgZGlkIG5vdCBhbnN3ZXIgYSBjZXJ0YWluIHF1ZXN0aW9uLCB3aHkgZGlkIHRoZXkgZG8gdGhhdD8gV2FzIHRoZSBxdWVzdGlvbiB1bmNsZWFyPyAgCkl0IHdvdWxkIGJlIGdvb2QgdG8gdW5kZXJzdGFuZCBleGFjdGx5IHdoYXQgdHlwZSBvZiBtaXNzaW5nIHZhbHVlIHdlIGFyZSBkZWFsaW5nIHdpdGguICAKCkxldCdzIHVzZSB0aGUgYG1pY2VgIHBhY2thZ2UgdG8gaGVscCB1cyB1bmRlcnN0YW50IGhvdyBhbGwgdGhlIE5BcyBiZWhhdmUgaW4gdGhlIGRhdGEuIGBtaWNlYCBwcm92aWRlcyBhIGhhbmR5IGZ1bmN0aW9uIGNhbGxlZCBgbWQucGF0dGVybmAgdGhhdCBhbGxvd3Mgb25lIHRvIHVuZGVyc3RhbmQgdGhlIHBhdHRlcm4gb2YgbWlzc2luZyBkYXRhLiBIb3BlZnVsbHkgYnkgbG9va2luZyBhdCB0aGUgcGF0dGVybiwgd2UgY2FuIGhhdmUgYW4gaWRlYSBvbiB3aHkgdGhlIGRhdGEgY291bGQgYmUgbWlzc2luZy4KYGBge3J9Cm1kLnBhdHRlcm4obW9uZXliYWxsKSAlPiUgZGF0YS5mcmFtZSgpCmBgYAoKVGhlICoqZmlyc3QgY29sdW1uKiogb2YgdGhlIG91dHB1dCBzaG93cyB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBtaXNzaW5nIGRhdGEgcGF0dGVybnMuIFRoZXJlIGFyZSAxOTEgb2JzZXJ2YXRpb25zIHdpdGggbm9ubWlzc2luZyB2YWx1ZXMsIGFuZCB0aGVyZSBhcmUgMTI5NSBvYnNlcnZhdGlvbnMgd2l0aCBub25taXNzaW5nIHZhbHVlcyBleGNlcHQgZm9yIHRoZSB2YXJpYWJsZSBiYXR0aW5nX2hicC4gVGhlICoqcmlnaHRtb3N0IGNvbHVtbioqIHNob3dzIHRoZSBudW1iZXIgb2YgKm1pc3NpbmcgdmFyaWFibGVzKiBpbiBhIHBhcnRpY3VsYXIgbWlzc2luZyBwYXR0ZXJuLiBGb3IgZXhhbXBsZSwgdGhlIGZpcnN0IHJvdyBoYXMgbm8gbWlzc2luZyB2YWx1ZSBhbmQgaXQgaXMg4oCcMOKAnSBpbiB0aGUgcm93LiBUaGUgKipsYXN0IHJvdyoqIGNvdW50cyB0aGUgbnVtYmVyIG9mIG1pc3NpbmcgdmFsdWVzIGZvciBlYWNoIHZhcmlhYmxlLiBGb3IgZXhhbXBsZSwgdGhlIHZhcmlhYmxlIHBpdGNoaW5nX2JiIGNvbnRhaW5zIG5vIG1pc3NpbmcgdmFsdWVzIGFuZCB0aGUgdmFyaWFibGUgYmF0dGluZ19zbyBjb250YWlucyAxMDIgbWlzc2luZyB2YWx1ZXMuIFRoaXMgdGFibGUgY2FuIGJlIGhlbHBmdWwgd2hlbiB5b3UgZGVjaWRlIHRvIGRyb3Agc29tZSBvYnNlcnZhdGlvbnMgd2l0aCBtaXNzaW5nIHZhcmlhYmxlcyBleGNlZWRpbmcgYSBwcmVzZXQgdGhyZXNob2xkLgoKCkFmdGVyIGRvaW5nIHNvbWUgcmVhZGluZyBpdCBsb29rcyBsaWtlIHRoYXQgY29sdW1ucyBjb3VsZCBiZSB0cmFuc2xhdGVkIHRvIGEgMCBvciAxLiBJIG5lZWQgdG8gZG8gbW9yZSBpbnZlc3RpZ2F0aW5nLgpGcm9tIHdvcmtpbmcgZXhwZXJpZW5jZSwgdXN1YWxseSBjb2x1bW5zIHdpdGggaGlnaCB2b2x1bWVzIG9mIE5BcyBpbmRpY2F0ZXMgaW1wb3J0YW50IGluZm9ybWF0aW9ucywgc2ltcGx5IGJlY2F1c2UgdGhleSBjb3VsZCBiZSBjYXB0dXJpbmcgcmFyZSBpbnN0YW5jZSB3aGVyZSBhIHByb2Nlc3MgZmFpbHMuIEluc3RlYWQgb2YgZGVsZXRpbmcgaXQsIEkgd2lsbCB0cnkgdG8gc2VlIGlmIEkgY2FuIHRyYW5zZm9ybSBpdCBpbnRvIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgd2l0aCAxcyBhbmQgMHMuIE5vdywgcmVnYXJkaW5nIHRoZSBvdGhlciBvbmUsIEkgd2lsbCB0cnkgc29tZSBvdGhlciBpbnB1dGF0aW9uIG1ldGhvZHMgc3VjaCBhcyBLTk4sIG1lYW4sIG1lZGlhbiwgZXRjLgoKCgojIyMgU3RlcCA1OiBJcyB0aGVyZSBjb2xsaW5lYXJpdHkgYW1vbmcgdGhlIGNvdmFyaWF0ZXM/CgpMZXQncyBjcmVhdGUgYSBzZXJpZXMgb2Ygc2NhdHRlciBwbG90cyB0byB1bmRlcnN0YW5kIGhvdyBlYWNoIGluZGVwZW5kZW50IHZhcmlhYmxlIGludGVyYWN0cyB3aXRoIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUuIFRoZXNlIHNjYXR0ZXIgcGxvdHMgd2lsbCBoZWxwIHVzIHNwb3QgYW55IGluZnJpZ2VtZW50IG9mIHRoZSBhc3N1cG10aW9ucyBuZWVkZWQgdG8gZGV2ZWxvcCBhIHJvYnVzdCBPTFMgbW9kZWwsIG5hbWVseSBtdWx0aWNvbGxpbmVhcml0eS4KCgpgYGB7ciB3YXJuaW5nID0gRkFMU0V9CmNoYXJ0LkNvcnJlbGF0aW9uKG1vbmV5YmFsbCwgaGlzdG9ncmFtID0gVFJVRSwgcGNoID0gMSwgbWV0aG9kID0gYygicGVhcnNvbiIpKQpgYGAKCkluIHRoZSBhYm92ZSBwbG90OgoKVGhlIGRpc3RyaWJ1dGlvbiBvZiBlYWNoIHZhcmlhYmxlIGlzIHNob3duIG9uIHRoZSBkaWFnb25hbC4KT24gdGhlIGJvdHRvbSBvZiB0aGUgZGlhZ29uYWwgOiB0aGUgYml2YXJpYXRlIHNjYXR0ZXIgcGxvdHMKd2l0aCBhIGZpdHRlZCBsaW5lIGRpc3BsYXllZCBvbiB0aGUgdG9wIG9mIHRoZSBkaWFnb25hbDogdGhlIHZhbHVlIG9mIHRoZSBjb3JyZWxhdGlvbiBwbHVzIHRoZSBzaWduaWZpY2FuY2UgbGV2ZWwgYXMgc3RhcnMuCkVhY2ggc2lnbmlmaWNhbmNlIGxldmVsIGlzIGFzc29jaWF0ZWQgdG8gYSBzeW1ib2w6IHAtdmFsdWVzKDAsIDAuMDAxLCAwLjAxLCAwLjA1LCAwLjEsIDEpIDw9PiBzeW1ib2xzKOKAnCoqKuKAnSwg4oCcKirigJ0sIOKAnCrigJ0sIOKAnC7igJ0sICIg4oCcKQoKQXMgd2UgZ28gYWNyb3NzIHRoZSBzZWNvbmQgcm93LCB3ZSBub3RpY2UgdGhhdCB2YXJpYWJsZXMgYXJlbid0IHN0cm9uZ2x5IGNvcnJlbGF0ZWQgdG8gb3VyIHRhcmdldCB2YXJpYWJsZS4gT25lIGNhbiBhbHNvIG5vdGljZSBjb3JyZWxhdGlvbiBudW1iZXJzIHVwIHRvIDAuOTcgYW1vbmcgb3VyIGluZGVwZW5kZW50IHZhcmlhYmxlcy4gVGhvc2UgdmFyaWFibGVzIHdpbGwgcG9zZSBhIHByb2JsZW0gd2hlbiB5b3UgaW5jbHVkZSB0aGVtIGluIGEgbW9kZWwuCgpUaGUgQ2FyZXQgcGFja2FnZSBvZmZlcnMgdGhlIGZpbmRjb3JyZWxhdGlvbigpLCB3aGljaCB0YWtlcyB0aGUgY29ycmVsYXRpb24gbWF0cml4IGFzIGFuIGlucHV0IGFuZCBmaW5kcyB0aGUgZmllbGRzIGNhdXNpbmcgbXVsdGljb2xsaW5lYXJpdHkgYmFzZWQgb24gYSB0aHJlc2hvbGQsIHRoZSBgY3V0b2ZmYCBwYXJhbWV0ZXIuIEl0IGluIHR1cm5zIHJldHVybnMgYSB2ZWN0b3Igd2l0aCB2YWx1ZXMgdGhhdCB3b3VsZCBuZWVkIHRvIGJlIHJlbW92ZWQgZnJvbSBvdXIgZGF0YXNldCBkdWUgdG8gY29ycmVsYXRpb24uIApgYGB7cn0KcGFzdGUwKCJOZWVkIHRvIGV4Y2x1ZGUgIiwgY29sbmFtZXMobW9uZXliYWxsKVtmaW5kQ29ycmVsYXRpb24oY29yKG1vbmV5YmFsbCkpXSkKYGBgCldlIHdpbGwgbmVlZCB0byByZXZpc2l0IHRoaXMgYWZ0ZXIgd2UgaGF2ZSBpbXB1dGVkL3Rha2VuIGNhcmUgb2YgTnVsbHMuCgojIyBEYXRhIFRyYW5zZm9ybWF0aW9uCgpCZWZvcmUgd2Ugc3RhcnQgc2NhbGluZywgY2VudGVyaW5nLCBvciBhcHBseSBhbnkgb3RoZXIgbW9kaWZpY2F0aW9uIHRvIHRoZSBkYXRhc2V0LCBsZXQgbWFrZSBzdXJlIHdlIGhhdmUgdGFrZW4gY2FyZSBvZiB0aGUgbnVsbCB2YWx1ZXMuCkxldCdzIGZpcnN0IGZvY3VzIG9uIHRoZSBjb2x1bW5zIHdpdGggdGhlIGhpZ2hlc3Qgdm9sdW1lIG9mIG51bGxzLCBgYmF0dGluZ19oYnBgLgoKRm9yIHRoaXMgY29sdW1uIHdlIHdpbGwgdHJ5IHRvIHRyYW5zZm9ybSBpdCBpbnRvIGEgYmluYXJ5IHZhcmlhYmxlLCAxcyBhbmQgMHMuIEkgZG9uJ3QgdW5kZXJzdGFuZCBiYXNlYmFsbCwgYnV0IGl0IHNlZW1zIHRoYXQgdGhpcyB2YXJpYWJsZSBpcyBub3QgbWlzc2luZyBhdCByYW5kb20sIHNvIHdlIGNvdWxkIHNpbXBsZSBzYXkgSGl0dCBieSBwaXRjaCBvciBub3QuIEkgd2lsbCBhbHNvIHNlZSBpZiBpbXB1dGF0aW9uIHVzaW5nIHRoZSBgTUlDRWAgcGFja2FnZSB3aWxsIGhlbHAgaW4gYW55IHdheS4KCmBgYHtyfQptb25leWJhbGxfdHJhbnMgPC0gbW9uZXliYWxsCmJhdHRpbmdfaGJwX2JpIDwtIGlmZWxzZShpcy5uYShtb25leWJhbGxfdHJhbnMkYmF0dGluZ19oYnApLDAsMSkgCm1vbmV5YmFsbF90cmFucyA8LSBzdWJzZXQobW9uZXliYWxsX3RyYW5zLCBzZWxlY3QgPSAtYyhiYXR0aW5nX2hicCkpICMgRHJvcHBpbmcgdGhlIHZhcmlhYmxlIHdlIGp1c3QgdHJhbnNmb3JtZWQuIAoKYGBgCgpOb3cgdGhhdCB0aGF0IHZhcmlhYmxlIGlzIHRha2VuIGNhcmUgb2YsIGxldCdzIHN0YXJ0IGltcHV0aW5nIG1pc3NpbmcgdmFsdWVzIHVzaW5nIG1pY2UuIFNpbmNlIHdlIG9ubHkgaGF2ZSBudW1lcmljIHZhbHVlcywgbWljZSB3aWxsIGF1dG9tYXRpY2FsbHkgY2hvc2UgUE1NIChQcmVkaWN0aXZlIE1lYW4gTWF0Y2hpbmcpCgoKYGBge3IgbWVzc2FnZSA9IEZBTFNFfQptaWNlX2ltcHV0ZXMgPC0gbWljZShtb25leWJhbGxfdHJhbnMsIG0gPSA1LCBtYXhpdCA9IDQwKQojV2hhdCBtZXRob2RzIHdlcmUgdXNlZCBmb3IgaW1wdXRpbmcKbWV0aG9kIDwtIG1pY2VfaW1wdXRlcyRtZXRob2QKIyBJIG9ubHkgaGF2ZSBudW1lcmljIHZhbHVlcywgbWljZSBjaG9zZSBQTU0gKFByZWRpY3RpdmUgTWVhbiBNYXRjaGluZykKCiNJbXB1dGVkIGRhdGFzZXQKbW9uZXliYWxsX3RyYW5zIDwtIGNvbXBsZXRlKG1pY2VfaW1wdXRlcywgNSkKbW9uZXliYWxsX3RyYW5zJGJhdHRpbmdfaGJwX2JpIDwtIGJhdHRpbmdfaGJwX2JpCmBgYAoKCk5vdyB0aGF0IHdlIGhhdmUgaW1wdXRlZCB0aGUgZGF0YSwgbGV0J3MgZG8gYSBxdWljayBzdW1tYXJ5IG9mIHRoZSBkYXRhIHRvIHNlZSBob3cgaXQgbG9va3MgbGlrZS4KYGBge3J9CnN1bW1hcnkobW9uZXliYWxsX3RyYW5zKQpgYGAKCmxldCdzIHRlc3QgYSBtb2RlbCB0byBlc3RhYmxpc2ggYSBiYXNlbGluZQoKYGBge3J9CmJhc2VfbW9kZWwgPC0gbG0odGFyZ2V0X3dpbnMgfi4sIGRhdGEgPSBtb25leWJhbGxfdHJhbnMpCnN0ZXB3aXNlX2Jhc2VfbW9kZWwgPC0gc3RlcEFJQyhiYXNlX21vZGVsLCBkaXJlY3Rpb24gPSAiYm90aCIpCnJvYnVzdF9iYXNlX21vZGVsIDwtIHJsbSh0YXJnZXRfd2lucyB+LiwgZGF0YSA9IG1vbmV5YmFsbF90cmFucykKc3VtbWFyeShzdGVwd2lzZV9iYXNlX21vZGVsKQpzdW1tYXJ5KGJhc2VfbW9kZWwpCnN1bW1hcnkocm9idXN0X2Jhc2VfbW9kZWwpCm1zZSA8LSBmdW5jdGlvbihzbSkgCiAgbWVhbihzbSRyZXNpZHVhbHNeMikKCm1zZShzdGVwd2lzZV9iYXNlX21vZGVsKQptc2UoYmFzZV9tb2RlbCkKbXNlKHJvYnVzdF9iYXNlX21vZGVsKQpgYGAKCkxldCdzIHVzZSBgY2FyZXRgIHByZXByb2Nlc3MgZnVuY3Rpb24gdG8gaGVscCB1cyBmaXggdGhlIGlzc3VlcyB3ZSBmb3VuZCB3aGlsZSBleHBsb3JpbmcgdGhlIGRhdGEuCgpGaXJzdCwgd2Ugd2lsbCB1c2UgYm94LWNveCB0byBub3JtYWxpemUgdGhlIGRhdGEuCgpgYGB7cn0KcHJvY2Vzc2VkIDwtIG11dGF0ZV9hbGwobW9uZXliYWxsX3RyYW5zWywxXSwgZnVuY3Rpb24oeCkgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoeCkpKQogICMgbWFraW5nIGEgY29weSB3aXRob3V0IHRoZSBpbmRleCBjb2x1bW4gc28gSSBkb24ndCBsb3NzZSBwcmV2aW91cyBzdGVwcwoKdHJhbnMgPC0gcHJlUHJvY2Vzcyhwcm9jZXNzZWQsIG1ldGhvZCA9ICJCb3hDb3giKQp0cmFuc2Zvcm1lZCA8LSBwcmVkaWN0KHRyYW5zLCBwcm9jZXNzZWQpCmJveF90ZXN0IDwtIEJveENveFRyYW5zKHByb2Nlc3NlZCRmaWVsZGluZ19lKQpoaXN0KHByZWRpY3QoYm94X3Rlc3QscHJvY2Vzc2VkJGZpZWxkaW5nX2UpKQpgYGAKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgpGaXJzdCB3ZSBzdGFydCB3aXRoIGEgcXVpY2sgYW5hCkxldCdzIGRvIGEgcXVpY2sgYW5hbHlzaXMgdG8gdW5kZXJzdGFuZCB0aGUgZGlzdHJpYnV0aW9uIG9mIE5BIHZhbHVlcyBhY2Nyb3NzIG91ciBkYXRhc2V0LiBMZXQncyBzb3J0IHRoZSBmaWVsZHMgd2l0aCBtb3N0IE5BcyBmcm9tIGhpZ2ggdG8gbG93LgoKYGBge3IgbWVzc2FnZT1GQUxTRX0KI2xldCBjaGVjayBmb3IgTkFzIGluIHRoZSBkYXRhCiNDb3VudGluZyB0aGUgbnVtYmVyIG9mIE5BcyBwZXIgY29sdW1uIGFuZCBjaGVjayB0aGUgcGVyY2VudGFnZSBvZiBOQXMgcGVyIGNvbHVtbgpOQVBlcmMgPC0gc2FwcGx5KG1vbmV5YmFsbCwgZnVuY3Rpb24oeCkgKHN1bShpcy5uYSh4KSkvbGVuZ3RoKHgpKSoxMDApICU+JQogIGRhdGEuZnJhbWUoKQpOQVBlcmMkQ29sdW1uIDwtIHJvd25hbWVzKE5BUGVyYykKY29sbmFtZXMoTkFQZXJjKSA8LSBjKCJOQV9QZXJjIiwgIkNvbF9OYW1lIikKc3Vic2V0KE5BUGVyYyxOQV9QZXJjID4gMCkgJT4lIGFycmFuZ2UoZGVzYyhOQV9QZXJjKSkKbWF0cml4cGxvdChtb25leWJhbGwpCmBgYApJdCdzIGNsZWFyIHRoYXQgVEVBTV9CQVRUSU5HX0hCUCBpcyBnb2luZyB0byBiZSBhIHByb2JsZW1hdGljIGNvbHVtbiB3aXRoIDkyJSBvZiB0aGUgZGF0YSBtaXNzaW5nLgpCZWZvcmUgd2Ugc3RhcnQgdGhlIGltcHV0YXRpb24sIGxldCdzIHRyeSB0byB1bmRlcnN0YW5kIHdoeSB3ZSBoYXZlIG1pc3NpbmcgZGF0YS4gCgoqKlRoZXJlIGFyZSB0d28gdHlwZXMgb2YgbWlzc2luZyBkYXRhKiogIAoKIC0gKk1DQVIqOiBtaXNzaW5nIGNvbXBsZXRlbHkgYXQgcmFuZG9tLiBUaGlzIGlzIHRoZSBkZXNpcmFibGUgc2NlbmFyaW8gaW4gY2FzZSBvZiBtaXNzaW5nIGRhdGEuICAKIC0gKk1OQVIqOiBtaXNzaW5nIG5vdCBhdCByYW5kb20uIE1pc3Npbmcgbm90IGF0IHJhbmRvbSBkYXRhIGlzIGEgbW9yZSBzZXJpb3VzIGlzc3VlIGFuZCBpbiB0aGlzIGNhc2UgaXQgbWlnaHQgYmUgd2lzZSB0byBjaGVjayB0aGUgZGF0YSBnYXRoZXJpbmcgcHJvY2VzcyBmdXJ0aGVyIGFuZCB0cnkgdG8gdW5kZXJzdGFuZCB3aHkgdGhlIGluZm9ybWF0aW9uIGlzIG1pc3NpbmcuIEZvciBpbnN0YW5jZSwgaWYgbW9zdCBvZiB0aGUgcGVvcGxlIGluIGEgc3VydmV5IGRpZCBub3QgYW5zd2VyIGEgY2VydGFpbiBxdWVzdGlvbiwgd2h5IGRpZCB0aGV5IGRvIHRoYXQ/IFdhcyB0aGUgcXVlc3Rpb24gdW5jbGVhcj8gIApJdCB3b3VsZCBiZSBnb29kIHRvIHVuZGVyc3RhbmQgZXhhY3RseSB3aGF0IHR5cGUgb2YgbWlzc2luZyB2YWx1ZSB3ZSBhcmUgZGVhbGluZyB3aXRoLiAgCgpMZXQncyB1c2UgdGhlIGBtaWNlYCBwYWNrYWdlIHRvIGhlbHAgdXMgdW5kZXJzdGFudCBob3cgYWxsIHRoZSBOQXMgYmVoYXZlIGluIHRoZSBkYXRhLiBgbWljZWAgcHJvdmlkZXMgYSBoYW5keSBmdW5jdGlvbiBjYWxsZWQgYG1kLnBhdHRlcm5gIHRoYXQgYWxsb3dzIG9uZSB0byB1bmRlcnN0YW5kIHRoZSBwYXR0ZXJuIG9mIG1pc3NpbmcgZGF0YS4gSG9wZWZ1bGx5IGJ5IGxvb2tpbmcgYXQgdGhlIHBhdHRlcm4sIHdlIGNhbiBoYXZlIGFuIGlkZWEgb24gd2h5IHRoZSBkYXRhIGNvdWxkIGJlIG1pc3NpbmcuCmBgYHtyfQptZC5wYXR0ZXJuKG1vbmV5YmFsbCkgJT4lIGRhdGEuZnJhbWUoKQpgYGAKCltIZXJlXShodHRwczovL3d3dy5yLWJsb2dnZXJzLmNvbS9pbXB1dGluZy1taXNzaW5nLWRhdGEtd2l0aC1yLW1pY2UtcGFja2FnZS8pIGlzIGEgZ3JlYXQgYXJ0aWNsZSBmcm9tIFJibG9nZ2VyIHRoYXQgZGlzY3Vzc2VzIHRoZSBwYWNrYWdlIFtNSUNFXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbWljZS9taWNlLnBkZikuCgoKCiMjIyBMZXQgdGhlIElucHV0YXRpb24gYmVnaW4KCmBgYHtyfQptb25leWJhbGxbaXMubmEobW9uZXliYWxsKSA9PSBUUlVFXSA8LSAwCm1iYWxsX2NvciA8LSBjb3IobW9uZXliYWxsKQpjb3JycGxvdChtYmFsbF9jb3IsIG1ldGhvZD0ibnVtYmVyIikKCgojIENvcnJlbGF0aW9uIHBhbmVsCnBhbmVsLmNvciA8LSBmdW5jdGlvbih4LCB5KXsKICAgIHVzciA8LSBwYXIoInVzciIpOyBvbi5leGl0KHBhcih1c3IpKQogICAgcGFyKHVzciA9IGMoMCwgMSwgMCwgMSkpCiAgICByIDwtIHJvdW5kKGNvcih4LCB5KSwgZGlnaXRzPTIpCiAgICB0eHQgPC0gcGFzdGUwKCJSID0gIiwgcikKICAgIGNleC5jb3IgPC0gMC44L3N0cndpZHRoKHR4dCkKICAgIHRleHQoMC41LCAwLjUsIHR4dCwgY2V4ID0gY2V4LmNvciAqIHIpCn0KIyBDdXN0b21pemUgdXBwZXIgcGFuZWwKdXBwZXIucGFuZWw8LWZ1bmN0aW9uKHgsIHkpewogIHBvaW50cyh4LHksIHBjaCA9IDE5KQp9CiMgQ3JlYXRlIHRoZSBwbG90cwpwYWlycyhtb25leWJhbGwsIAogICAgICBsb3dlci5wYW5lbCA9IHBhbmVsLmNvciwKICAgICAgdXBwZXIucGFuZWwgPSB1cHBlci5wYW5lbCkKY29yLmNpKG1vbmV5YmFsbCwgbWV0aG9kPSJzcGVhcm1hbiIpCmBgYApUaGUgQ2FyZXQgcGFja2FnZSBvZmZlcnMgdGhlIGZpbmRjb3JyZWxhdGlvbigpLCB3aGljaCB0YWtlcyB0aGUgY29ycmVsYXRpb24gbWF0cml4IGFzIGFuIGlucHV0IGFuZCBmaW5kcyB0aGUgZmllbGRzIGNhdXNpbmcgbXVsdGljb2xsaW5lYXJpdHkgYmFzZWQgb24gYSB0aHJlc2hvbGQsIHRoZSBgY3V0b2ZmYCBwYXJhbWV0ZXIuIEl0IGluIHR1cm5zIHJldHVybnMgYSB2ZWN0b3Igd2l0aCB2YWx1ZXMgdGhhdCB3b3VsZCBuZWVkIHRvIGJlIHJlbW92ZWQgZnJvbSBvdXIgZGF0YXNldCBkdWUgdG8gY29ycmVsYXRpb24uIAojIyBSZWZlcmVuY2UKCiAtIFtNaXNzaW5nIGRhdGEgZXhwbG9yYXRpb246IGhpZ2hsaWdodGluZyBncmFwaGljYWwgcHJlc2VudGF0aW9uIG9mIG1pc3NpbmcgcGF0dGVybl0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wbWMvYXJ0aWNsZXMvUE1DNDcwMTUxNy8pCgoKCg==